import re

import openpyxl
import pandas as pd
from pandas import DataFrame

from apps.query_db import get_all_sdtm_variable


def custom_variable_sort(to_sort_list, all_variable_list, domain):
    # 创建一个排序字典，映射排序权重
    order_dict = {}
    # 处理通配符
    for index, var in enumerate(all_variable_list):
        if var.startswith('--'):
            wildcard_replaced = var.replace('--', domain)
            order_dict[wildcard_replaced] = index
        else:
            order_dict[var] = index

    # 对需要排序的列表进行排序，根据它们在 order_dict 中的位置
    # 如果变量不在 order_dict 中，就将其放在列表的末尾
    sorted_list = sorted(to_sort_list, key=lambda x: order_dict.get(x, float('inf')))
    return sorted_list


# 移除第一张表格
def remove_first_sheet(path):
    book = openpyxl.load_workbook(path)
    # 如果只有第一张默认表，则直接返回，不删除
    if len(book.sheetnames) == 1:
        return
    sheet = book['Sheet']
    book.remove(sheet)
    book.save(path)
    book.close()


# 解析每个域对应的表格以及每个表对应的域
# @param dataset_df_dic: 数据集字典
# @return: 域到表名的映射(一个域可能对应多个表), 表名到域的映射
def sheet_parse(dataset_df_dic: dict[str, DataFrame]):
    domain_to_sheet_dict = {}  # 域到表名的映射, 一个域可能对应多个表
    sheet_to_domain_dict = {}  # 表名到域的映射
    # 遍历每张表
    for sheet_name, df in dataset_df_dic.items():
        # 存在DOMAIN列，并且至少一行数据且第一行的DOMAIN字段不为空
        if 'DOMAIN' in df.columns.tolist() and (0 in df.index) and pd.notna(df.loc[0, 'DOMAIN']):
            domain = df.loc[0, 'DOMAIN']
            lst = domain_to_sheet_dict.get(domain, [])
            lst.append(sheet_name)
            domain_to_sheet_dict[domain] = lst
            sheet_to_domain_dict[sheet_name] = domain
    return domain_to_sheet_dict, sheet_to_domain_dict



'''
解析衍生方法
输入：                                  输出：
"X1 = 原始/DM/SITEID                    variable_lst: ["原始/DM/SITEID ", "project/DM/SUBJID"]
X2 = project/DM/SUBJID                            
###                 ===============》  _params: X1,X2
if X1 != 1:                           
    return X1+X2"                      expression_lst:["if X1 != 1:", "    return X1+X2"]
'''


def code_handle(code: str) -> (list, list, str):
    if code is None:
        return None, None, None
    if code == "None":
        return None, None, None
    _lines = code.split("\n")
    for i in range(len(_lines)):
        _lines[i] = _lines[i].strip('\r')
    if "###" not in _lines:
        return [], "", str(_lines[0])
    else:
        index = _lines.index("###")
        param_lst = _lines[:index]
        expression_lst = str(_lines[index + 1:][0])
        variable_lst = []
        _params = []
        for param in param_lst:
            lst = param.split("=")
            left = lst[0].strip()
            right = lst[1].strip()
            variable_lst.append(right)
            _params.append(left)
        return variable_lst, _params, expression_lst


# 获取标准受控术语和自定义受控术语的映射关系
# code-应用名称-数值含义-展示顺序-匹配数据-递交值
# C20197@#$男性@#$2@#$2@#$2@#$M |-| C16576@#$女性@#$1@#$1@#$1@#$F
# 自定义术语的格式： 字典名称-描述-键值-序号-键值
# 例如： 因果关系@#$肯定有关@#$1@#$1@#$1;因果关系@#$可能有关@#$2@#$2@#$2
def get_ct_mapping(ct_code: str, ct_type: str) -> dict:
    _index = 4  # 匹配数据对应的下标
    dic = {}
    code_list = ct_code.split('|-|')  # 术语列表
    for code in code_list:
        code = code.strip()
        code = code.split('@#$')  # 拆分术语不同字段
        # 标准受控术语，只有一个术语且未填写匹配数据
        # 则默认为*， 代表这一列都填充为这一个固定值（取递交值）
        if len(code_list) == 1 and len(code) == 6 and (
                code[_index] == '' or code[_index] == 'null'):  # ’C49488-是-null-1-null‘ 类型
            dic['*'] = code[5]
            break
        else:
            if code[_index] != '' and code[_index] != 'null':
                number_lst = []  # 数据匹配列表
                if code[_index] != '' and code[_index] != 'null':
                    number_lst.append(code[_index])
                # 有可能多个数值匹配同一个递交值， # ’C41340-重度-3-3-3,4-重度‘ 类型
                if ',' in code[_index] or '，' in code[_index]:
                    if ',' in code[_index]:
                        number_lst = code[_index].split(',')
                    else:
                        number_lst = code[_index].split('，')
                for num in number_lst:
                    if ct_type == '标准':  # 标准受控术语将数值匹配为递交值
                        try:  # 尝试将字符串转换为整数， 因为‘匹配数据’字段可能是按描述匹配，填的是字符串，不一定是数字
                            dic[int(num)] = code[5]
                        except ValueError:
                            print(f"无法将'{num}'转换为整数")
                        dic[num] = code[5]
                    if ct_type == '自定义':  # 自定义受控术语将键值匹配为描述
                        try:
                            dic[int(num)] = code[1]
                        except ValueError:
                            print(f"无法将'{num}'转换为整数")
                        dic[num] = code[1]
    return dic


# 提取原始数据集表头字段的英文部分
def extract_english_fields(input_file, output_file):
    # 读取excel文件为ExcelFile对象
    excel_file = pd.ExcelFile(input_file)

    with pd.ExcelWriter(output_file, engine='openpyxl') as writer:
        for sheet_name in excel_file.sheet_names:
            # 读取当前sheet的数据到DataFrame
            df = pd.read_excel(input_file, sheet_name=sheet_name,
                               converters={'受试者筛选号/SUBJID': str, '研究中心编号/SITEID': str})

            # 提取每列名中最后一个"/"之后的文本
            df.columns = [col.split('/')[-1].strip() if '/' in col else col for col in df.columns]

            # 输出到新的excel文件（每个sheet单独输出）
            df.to_excel(writer, sheet_name=sheet_name, index=False)


# 将日期格式转换为ISO 8601标准格式
def convert_to_iso8601(df, column, dtype) -> DataFrame:
    def parse_date(date_str):
        # 确保数据是字符串类型，否则转换为字符串
        if not isinstance(date_str, str):
            if pd.isna(date_str):
                return ""
            date_str = str(date_str)
        # 使用更精确的正则表达式匹配年月日和时间
        datetime_match = re.match(r'(\d{4}-\d{2}-\d{2})(?: (\d{1,2})(?::(\d{2})(?::(\d{2}))?)?)?', date_str)
        if datetime_match:
            date_part, hour, minute, second = datetime_match.groups()
            if hour:
                minute = minute if minute else "00"
                second = second if second else "00"
                time_part = f"{hour.zfill(2)}:{minute}:{second}"
                if dtype == 'datetime' or dtype == 'Datetime':
                    return f"{date_part}T{time_part}"  # 按ISO 8601格式返回日期和时间
                elif dtype == 'date' or dtype == 'Date':
                    return date_part  # 仅返回日期部分
            else:
                if dtype == 'datetime' or dtype == 'Datetime':
                    return f"{date_part}T00:00:00"  # 如果是datetime类型，补全时间为00:00:00
                elif dtype == 'date' or dtype == 'Date':
                    return date_part

        # 如果没有匹配到日期时间，尝试仅匹配年份
        year_match = re.match(r'(\d{4})', date_str)
        if year_match:
            return year_match.group(0)  # 仅返回年份

        # 如果没有有效的日期或时间信息，则返回空字符串
        return ""

    # 应用转换函数到指定列
    df[column] = df[column].apply(parse_date)
    return df


if __name__ == '__main__':
    # dic = get_ct_mapping("test110@#$否@#$@#$2@#$|-|test110@#$是@#$@#$1@#$|-|test110@#$未知@#$@#$3@#$")
    # project_id = '86af5e3968c9455aad692acf7037f29b'
    # df_dic = get_combined_dataframe(project_id)
    # dt1, dt2 = sheet_parse(df_dic)
    # for key, value in dt1.items():
    #     print(key, value)
    # for key, value in dt2.items():
    #     print(key, value)

    # 示例用法
    # data = {
    #     'date_column': ['2020-02-28 09', '2020-02-28 09:12:35', '1963-09-02', '1955-UK-UK']
    # }
    # df = pd.DataFrame(data)
    # print("原始 DataFrame:")
    # print(df)
    #
    # # 转换日期时间列为 datetime 类型
    # df_datetime = convert_to_iso8601(df.copy(), 'date_column', 'datetime')
    # print("\n转换为 datetime 后的 DataFrame:")
    # print(df_datetime)
    #
    # # 转换日期时间列为 date 类型
    # df_date = convert_to_iso8601(df.copy(), 'date_column', 'date')
    # print("\n转换为 date 后的 DataFrame:")
    # print(df_date)

    # 示例数据
    # data = {
    #     'date_column': ['2020-02-28 09', '2020-02-28 09:12:35', '1963-09-02', '1955-UK-UK']
    # }
    to_sort_list = ['USUBJID', 'DOMAIN', 'AETERM', 'STUDYID']
    all_variable_list = get_all_sdtm_variable()
    domain = 'AE'

    # 调用自定义排序函数
    sorted_list = custom_variable_sort(to_sort_list, all_variable_list, domain)
    print(sorted_list)

